<template>
	<div class="upload-container">
		<uploadAttachment v-if="isDialog" ref="attachmentRef" :accept="accept" :limit="limit" :size="size" type="file" @confirm="uploadConfirm">
			<el-button class="upload-empty cursor-pointer" @click="uploadFileBtn" :disabled="disabled" type="primary">
				<el-icon class="el-icon--right"><ele-Upload /></el-icon>上传文件
			</el-button>
		</uploadAttachment>
		<template v-else>
			<el-upload
				ref="uploadRef"
				:action="uploadData.action"
				:headers="uploadData.headers"
				:data="uploadData.params"
				:multiple="limit > 1 ? true : false"
				:disabled="disabled"
				:accept="accept"
				:drag="drag"
				:limit="limit"
				:show-file-list="false"
				:on-progress="uploadProgress"
				:before-upload="handleBeforeUpload"
				:on-change="handleChange"
				:on-success="handleSuccess"
				:on-exceed="handleExceed"
				:on-error="handleError"
			>
				<div class="upload-btn w-[300px] h-[98px]" v-if="drag">
					<SvgIcon name="local-icon-upload" :size="50" />
					<div class="el-upload__text">
						<div class="el-upload__text">拖拽放入 或 <em>点击上传</em></div>
					</div>
				</div>
				<el-button v-else class="upload-empty cursor-pointer" @click="uploadFileBtn" :disabled="disabled" type="primary">
					<el-icon class="el-icon--right"><ele-Upload /></el-icon>上传文件
				</el-button>
			</el-upload>
		</template>
	</div>
	<ul class="file-list">
		<li class="list-item" v-for="(item, index) in fileList.data" :key="index">
			<div class="relative">
				<div class="item-info">
					<a class="file-info">
						<SvgIcon :name="getFileIcon(item.name)" :size="15" class="file-icon" />
						<el-tooltip
							effect="dark"
							:content="item.name"
						>
							<span class="file-name">{{ item.name }}</span>
						</el-tooltip>
					</a>
				</div>
				<div class="item-status-label">
					<SvgIcon name="ele-CircleCheck" class="file-icon file-success" :size="15" />
					<SvgIcon name="ele-Close" v-if="!disabled" class="file-icon file-close" :size="16" @click="deleteFile(index)" />
					<SvgIcon name="ele-Download" v-if="!item.progressFlag && download" class="file-icon file-download" :size="15" v-down="downloadFile(item)" />
				</div>
			</div>
			<el-progress v-if="item.progressFlag && progress" :percentage="item.percentage" class="ml-[6px]"></el-progress>
		</li>
	</ul>
	<div class="el-upload__tip upload-tip-text">{{ promptText }}</div>
</template>
<script lang="ts" setup>
import { computed, reactive, ref, watch, toRaw } from 'vue';
import { messageError } from '/@/utils/message';
import type { UploadInstance } from 'element-plus';
import { Local } from '/@/utils/storage';
import { getFileInfo, getFileOrder, getFileItem, getUrl } from '/@/utils/util';

const { VITE_API_URL } = import.meta.env;

const props = defineProps({
	modelValue: {
		type: String,
		required: true,
		default: '',
	},
	// 是否弹框打开
	isDialog: {
		type: Boolean,
		required: false,
		default: true,
	},
	// 提示文字
	promptText: {
		type: String,
		required: false,
		default: '',
	},
	// 是否显示进度条
	progress: {
		type: Boolean,
		required: false,
		default: true,
	},
	// 是否禁用
	disabled: {
		type: Boolean,
		required: false,
		default: false,
	},
	// 是否拖拽
	drag: {
		type: Boolean,
		required: false,
		default: false,
	},
	// 是否下载
	download: {
		type: Boolean,
		required: false,
		default: true,
	},
	// 限制上传数量
	limit: {
		default: 1,
		required: false,
		type: Number,
	},
	// 接受上传的文件类型
	accept: {
		type: String,
		required: false,
		default: '.zip,.rar,.doc,.docx,.pdf,.ppt,.pptx,.txt,.xls,.xlsx',
	},
	// 限制上传大小，单位:kb
	size: {
		type: Number,
		required: false,
		default: 10000,
	},
	// 上传文件名称
	name: {
		type: Number,
		required: false,
		default: '',
	},
	// 上传文件目录
	saveDir: {
		type: String,
		required: false,
		default: '',
	},
});

const emit = defineEmits(['update:modelValue', 'change']);

const fileValue = computed({
	get() {
		return props.modelValue;
	},
	set(value) {
		emit('update:modelValue', value);
	},
});

const attachmentRef = ref(null);

const fileList = reactive({
	data: [],
});

const uploadRef = ref<UploadInstance>();

const uploadData = reactive({
	action: `${VITE_API_URL}/admin/upload/file`,
	params: <any>{},
	headers: {
		Authorization: Local.get('token'),
	},
});

const setValue = () => {
	fileValue.value = toRaw(fileList.data)
		.map((item: any) => {
				return item.url;
			})
			.toString();
};

watch(
	() => fileValue.value,
	() => {
		// 初始赋值
		if (fileValue.value.length && !fileList.data.length) {
			fileList.data = fileValue.value.split(',').map((url: string) => {
				return getFileItem(url, '');
			});
		}
		setValue();
	},
	{ immediate: true }
);

// 上传文件
const uploadFileBtn = () => {
	if (!props.disabled) {
		if (props.isDialog) attachmentRef.value.openDialog();
	}
};

// 上传进度条
const uploadProgress = (event: any, file: any, fileLists: any[]) => {
	let isAdd = true;
	let rawFile = file.raw;
	toRaw(fileList.data).map((item, index) => {
		if (item.uid == rawFile.uid) {
			isAdd = false;
			fileList.data[index].percentage = parseInt(event.percent);
		}
	});
	if (isAdd) {
		if (props.limit == 1) fileList.data.splice(0, 1);
		fileList.data.push({ name: rawFile.name, url: '', percentage: rawFile.percentage, progressFlag: true, uid: rawFile.uid, file: file });
	}
};

// 附件组件选择完成
const uploadConfirm = (data: Record<string, any>) => {
	if (props.limit == 1) {
		fileList.data.splice(0, 1);
		data && fileList.data.push(getFileItem(data.url, ''));
	} else {
		const data_order = getFileOrder(data); //重新排序
		if (fileList.data.length < props.limit) {
			fileList.data.push(...data_order.slice(0, props.limit - fileList.data.length));
		}
	}
	setValue();
	emit('change', fileValue.value);
};

// 上传之前
const handleBeforeUpload = () => {
	if (props.accept && props.accept != '*/*') uploadData.params['ext'] = props.accept.split('.').join('');
	if (props.size) uploadData.params['size'] = props.size * 1024;
	if (props.name) uploadData.params['name'] = props.name;
	if (props.saveDir) uploadData.params['save_dir'] = props.saveDir;
};

// 上传检验
const handleChange = (file: any, fileLists: any[]) => {
	if (file.status !== 'ready') return;
	let rawFile = file.raw;
	let fileSize = rawFile.size / 1024;
	let fileType = rawFile.name.split('.').pop();
	let acceptArr = props.accept.split('.').join('').split(',');

	if (!acceptArr.includes(fileType.substring(fileType.lastIndexOf('/') + 1, fileType.length))) {
		messageError('上传文件格式不符！');
		fileLists.splice(-1, 1);
		return false;
	}
	if (props.size && fileSize > props.size) {
		messageError('文件大小不能超过' + props.size + 'KB!');
		fileLists.splice(-1, 1);
		return false;
	}

	if (fileList.data.length + fileLists.length > props.limit) {
		if(props.isDialog) {
			fileLists.splice(-1, 1);
			return false;
		} else {
			fileList.data.splice(-1, 1);
		}
	}
};

// 上传成功
const handleSuccess = (response: any, file: any, fileLists: any[]) => {
	const allSuccess = fileLists.every((item) => item.status == 'success');
	if (allSuccess) {
		uploadRef.value?.clearFiles();
	}
	if (response.code == 0) {
		toRaw(fileList.data).map((item, index) => {
			if (item.uid == toRaw(file).uid) {
				fileList.data[index].uri = response.data.uri;
				fileList.data[index].url = response.data.url;
				fileList.data[index].percentage = 100;
				setTimeout(() => {
					fileList.data[index].progressFlag = false;
				}, 500);
			}
		});
	} else {
		fileList.data.splice(-1, 1);
		messageError(response.msg);
	}
	setValue();
	emit('change', fileValue.value);
};

// 上传提示
const handleExceed = () => {
	messageError(`最多可以上传${props.limit}个文件`);
};

// 上传错误
const handleError = (event: any, file: any) => {
	messageError(`${file.name}文件上传失败`);
	uploadRef.value?.abort(file);
};

// 删除文件
const deleteFile = (index) => {
	let file = fileList.data[index].file;
	let percentage = fileList.data[index].percentage;
	// 取消上传中的文件
	if (file && percentage < 100) {
		uploadRef.value?.abort(file);
		uploadRef.value?.handleRemove(file);
	}
	fileList.data.splice(index, 1);
	setValue();
};

// 获取图标信息
const getFileIcon = (name: string) => {
	return 'local-icon-' + getFileInfo(name, true)['iconName'];
};

// 下载文件
const downloadFile = (item:any) => {
	return [getUrl(item.url),item.name,true];
};

defineExpose({
	deleteFile
});
</script>

<style lang="scss" scoped>
.upload-container {
	display: flex;
	justify-content: left;
	width: 100%;
	flex-wrap: wrap;
}

.file-list {
	margin: 10px 0 0;
	padding: 0;
	list-style: none;
	position: relative;
	.list-item {
		transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
		font-size: 14px;
		color: var(--el-text-color-regular);
		margin-bottom: 5px;
		position: relative;
		box-sizing: border-box;
		border-radius: 4px;
		width: 100%;
		.item-info {
			display: inline-flex;
			justify-content: center;
			flex-direction: column;
			width: calc(100% - 50px);
			margin-left: 4px;

			.file-info {
				color: var(--el-text-color-regular);
				display: inline-flex;
				text-align: center;
				align-items: center;
				padding: 0 4px;
				transition: color var(--el-transition-duration);
				font-size: var(--el-font-size-base);

				.file-icon {
					margin-right: 6px;
					color: var(--el-text-color-secondary);
					width: 1em;
				}

				.file-name {
					overflow: hidden;
					text-overflow: ellipsis;
					white-space: nowrap;
				}
				&:hover {
					color: var(--el-color-primary);
					cursor: pointer;
				}
			}
		}
		.item-status-label {
			position: absolute;
			right: 5px;
			top: 0;
			line-height: inherit;
			display: inline-flex;
			height: 100%;
			justify-content: center;
			align-items: center;
			transition: opacity var(--el-transition-duration);

			.file-icon {
				display: inline-flex;
				position: absolute;
				top: 50%;
				cursor: pointer;
				opacity: 0.75;
				color: var(--el-text-color-regular);
				transition: opacity var(--el-transition-duration);
				transform: translateY(-50%);
				&:hover {
					opacity: 1;
					color: var(--el-color-primary);
				}
			}

			.file-success {
				right: 27px;
				color: var(--el-color-success);
			}
			.file-close {
				display: none;
				right: 27px;
			}
			.file-download {
				right: 7px;
			}
		}
		&:hover {
			background-color: var(--el-fill-color-light);
			.file-success {
				display: none;
			}
			.file-close {
				display: inline-flex;
			}
		}
	}
}

.upload-tip-text {
	color: #999;
	margin-top: 0;
}
</style>